# --------------------------------数据爬虫--------------------------------------

from bs4 import BeautifulSoup
import requests
import pandas as pd

def extract_numbers(s):
    numbers = ""
    for char in s:
        if char.isdigit():  # 检查字符是否为数字
            numbers += char
    return numbers
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0'}
urls = ["https://lz.esf.fang.com", "https://lz.esf.fang.com/house/i32"]
url_all = []
Building_Total = []
Building_Height = []
Building_Interior_Layout = []
Building_Area = []
Building_Floor = []
Building_Orientation = []
Building_Price_Right = []
Building_Resource = []
Building_Price = []
Building_Decoration = []
Building_Property_Type = []
Building_Type = []
Building_Residential_Category =[]
Building_Architectural_Structure = []
Building_Category = []
Building_Elevator = []
Building_Age = []
Building_Region = []
for url in urls:
    content = requests.get(url, headers=headers).text
    soup = BeautifulSoup(content, "html.parser")
    all_span=soup.find_all('span',attrs={'class':'red'})
    all_h4 = soup.find_all('h4')
    all_dl=soup.find_all('dl')
    all_dd = soup.find_all('dd')
    all_dd_price = soup.find_all('dd', attrs={'class': 'price_right'})
    for span in all_span:
        Building_Price.append(span.b.string)
    for price in all_dd_price:
        price = price.find_all('span')
        Building_Price_Right.append(price[1].string)  # 均价)
    for h4 in all_h4:
        a_all = h4.find_all('a')
        if h4.find('a'):
            url_h4=h4.find('a')['href']
            url_all.append(url+url_h4)
        if len(a_all) >= 1:
            a = a_all[0]
        if a:
            all_total_span = a.find_all('span', attrs={'class': 'tit_shop'})
            for span in all_total_span:
                Building_Total.append(span.contents)  # 总览
    for dd in all_dd:
        p = dd.find_all('p')
        if len(p) >= 1:
            dd_p0 = p[0]
        if dd_p0 and len(p) >= 1:
            contents = dd_p0.contents
            S = []
            for s in contents:
                if isinstance(s, str):
                    S.append(s)
            Building_Interior_Layout.append(S[0])
            Building_Area.append(S[1])
            Building_Floor.append(extract_numbers(S[2]))
            Building_Orientation.append(S[3])
            all_height_a = dd_p0.find_all('a', attrs={'class': 'link_rk'})
            for a in all_height_a:
                Building_Height.append(a.string)  # 楼层
    for dl in all_dl:
        dd = dl.find_all('dd')
        if dd and dd != []:
            ps = dd[0].find_all('p')
            if ps and ps != []:
                Building_Resource.append(ps[1].a.string)
            else:
                Building_Resource.append('数据缺失')
for urll in url_all[0:60]:
    content = requests.get(urll, headers=headers).text
    soup = BeautifulSoup(content, "html.parser")
    print(urll)
    all_div = soup.find_all('div',attrs={'class':'trl-item1 w132'})
    all_reg = soup.find_all('div',attrs={'class':'trl-item2 clearfix'})
    div_div_pro = soup.find_all('div',attrs={'class':'text-item clearfix'})
    for i in all_reg:
        all_reg_pro = i.find('div', attrs={'class': 'rcont'})
        if len(all_reg_pro) >= 1:
            Building_Region.append(all_reg_pro.a.string)
        else:
            Building_Region.append('数据缺失')
    x = 0
    if len(div_div_pro) >= 1:
        if extract_numbers(div_div_pro[x].contents[1].string):
            Building_Age.append(div_div_pro[0].contents[1].string)
            x = 1
        else:
            Building_Age.append('数据缺失')
    if len(div_div_pro) >= x+1 and div_div_pro[x].contents[0].string == '有无电梯':
        Building_Elevator.append(div_div_pro[x].contents[1].string)
    else:
        Building_Elevator.append('数据缺失')
    if len(div_div_pro) >= x+2 and div_div_pro[x+1].contents[0].string == '产权性质':
        Building_Property_Type.append(div_div_pro[x+1].contents[1].string)
    else:
        Building_Property_Type.append('数据缺失')
    if len(div_div_pro) >= x+3:
        Building_Residential_Category.append(div_div_pro[x+2].contents[1].string)
    else:
        Building_Residential_Category.append('数据缺失')
    if len(div_div_pro) >= x+4:
        Building_Architectural_Structure.append(div_div_pro[x+3].contents[1].string)
    else:
        Building_Architectural_Structure.append('数据缺失')
    if len(div_div_pro) >= x+5:
        Building_Category.append(div_div_pro[x+4].contents[1].string)
    else:
        Building_Category.append('数据缺失')
    for i in all_div:
        dec = i.div
        if dec.a:
            Building_Decoration.append(dec.a.string)
        else:
            Building_Decoration.append('数据缺失')
data = {
    '房源': Building_Resource[0:60],
    '区域': Building_Region[0:60],
    '建筑年代': Building_Age[0:60],
    '电梯': Building_Elevator[0:60],
    '产权性质': Building_Property_Type[0:60],
    '住宅类别': Building_Residential_Category[0:60],
    '建筑结构': Building_Architectural_Structure[0:60],
    '建筑类别': Building_Category[0:60],
    '楼层': Building_Height[0:60],
    '布局': Building_Interior_Layout[0:60],
    '面积': Building_Area[0:60],
    '层数': Building_Floor[0:60],
    '朝向': Building_Orientation[0:60],
    '装修': Building_Decoration[0:60],
    '单价(元/m²)': Building_Price_Right[0:60],
    '总价（万元）': Building_Price[0:60]
}
df = pd.DataFrame(data)
df.to_csv("Buildings_finall.csv",encoding='utf_8_sig',index=False)
print(df)

# ---------------------------------------------数据处理--------------------------------------

'''
数据清洗
'''
import pandas as pd
import  numpy as np
import  re
import warnings
import matplotlib.pyplot as plt
warnings.filterwarnings('ignore')

# 读取CSV文件
house_data = pd.read_csv("Buildings_finall.csv")

# 将数据转换为DataFrame
pd.DataFrame(house_data)

# 数据预览
print(house_data.shape)  # 打印数据的维度
print(house_data.info())  # 打印数据的基本信息，包括列名、数据类型和非空值数量
print(house_data.describe())  # 打印数值型列的统计信息，如均值、标准差、最小值、最大值等

# 初始化一个字典，用于存储每列的缺失值个数
missing = {}

# 遍历DataFrame的每一列
for column in house_data.columns:
    # 计算当前列的缺失值个数
    missing_count = house_data[column].isnull().sum()
    # 将计算结果存入字典
    missing[column] = {'missing': missing_count}

# 打印各列的缺失值个数
for column, info in missing.items():
    print(f"列名: {column}, 缺失值个数: {info['missing']}")


# 选项类异常值处理
house_data['建筑年代'] = house_data['建筑年代'].str.replace('年', '')  # 去除“年”字
house_data['建筑年代'] = pd.to_datetime(house_data['建筑年代'], errors='coerce')  # 将建筑年代转换为日期类型
house_data['建筑年代'] = house_data['建筑年代'].dt.year  # 提取年份

# 对“电梯”列进行异常值处理
house_data['电梯'] = house_data['电梯'].str.strip()  # 去除字符串两端的空格
lift = ['有', '无']  # 定义有效的电梯选项
house_data.loc[~house_data['电梯'].isin(lift), '电梯'] = np.nan  # 将不在有效选项内的值设为NaN

# 对“产权性质”列进行异常值处理
Nature_of_property_rights = ['个人产权']  # 定义有效的产权性质选项
house_data.loc[~house_data['产权性质'].isin(Nature_of_property_rights), '产权性质'] = np.nan

# 对“装修”列进行异常值处理
fitment = ['毛坯', '精装修', '简装修']  # 定义有效的装修选项
house_data.loc[~house_data['装修'].isin(fitment), '装修'] = np.nan

# 对“建筑结构”列进行异常值处理
house_data['建筑结构'] = house_data['建筑结构'].str.strip()
Building_Structure = ['平层']  # 定义有效的建筑结构选项
house_data.loc[~house_data['建筑结构'].isin(Building_Structure), '建筑结构'] = np.nan

# 对“建筑类别”列进行异常值处理
house_data['建筑类别'] = house_data['建筑类别'].str.strip()
Building_Category = ['板楼']  # 定义有效的建筑类别选项
house_data.loc[~house_data['建筑类别'].isin(Building_Category), '建筑类别'] = np.nan

# 对“住宅类别”列进行异常值处理
house_data['住宅类别'] = house_data['住宅类别'].str.strip()
Building_Structure = ['普通住宅']  # 定义有效的住宅类别选项
house_data.loc[~house_data['住宅类别'].isin(Building_Structure), '住宅类别'] = np.nan

# 初始化一个字典，用于存储每列的缺失值个数
missing = {}

# 遍历DataFrame的每一列
for column in house_data.columns:
    # 计算当前列的缺失值个数
    missing_count = house_data[column].isnull().sum()
    # 将计算结果存入字典
    missing[column] = {'missing': missing_count}

# 打印各列的缺失值个数
for column, info in missing.items():
    print(f"列名: {column}, 缺失值个数: {info['missing']}")

#注：
#对于缺失值的处理，在画图时对单个列进行处理避免对整体数据的影响
#对于重复值的处理，在画图时对相应列进行分组聚合处理避免对整体数据的影响

# 处理单位
data_digit = ['面积', '单价(元/m²)']
for column in data_digit:
    house_data[column] = house_data[column].apply(lambda x: re.sub(r'[^\d.-]', '', x))
    # 去除非数字和非小数点字符

# 打印唯一标签值
for column in ['区域', '建筑年代', '电梯', '布局', '产权性质', '面积', '层数', '住宅类别', '建筑结构', '建筑类别',
               '朝向', '楼层', '装修', '单价(元/m²)', '总价（万元）']:
    print(house_data[column].unique())  # 打印每列的唯一值

# 再次打印数据的维度、基本信息和统计信息
print(house_data.shape)
print(house_data.info())
print(house_data.describe())

# 打印处理后的缺失值个数
for column, info in missing.items():
    print(f"列名: {column}, 缺失值个数: {info['missing']}")

# 打印处理后的数据
print(house_data)

# 将处理后的数据保存到CSV文件
house_data.to_csv("Buildings_finall_handle.csv", encoding='utf_8_sig', index=False)

# ----------------------------------------------------------可视化--------------------------------------
import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import ListedColormap
import warnings
warnings.filterwarnings('ignore')  # 屏蔽所有警告信息

# 或者只屏蔽特定类型的警告
# 屏蔽 FutureWarning 类型的警告
warnings.filterwarnings('ignore', category=FutureWarning)

plt.rcParams['font.sans-serif']=['SimHei'] #将字体设置为支持中文
plt.rcParams['axes.unicode_minus']=False #正常显示符号


#1
df = pd.read_csv('Buildings_finall_handle.csv')
df = df.dropna(subset=['面积', '总价（万元）'])
df['面积'] = pd.to_numeric(df['面积'])
df['总价（万元）'] = pd.to_numeric(df['总价（万元）'])

plt.figure(figsize=(10, 6))
sns.scatterplot(x='面积', y='总价（万元）', data=df)
plt.title('面积与总价的关系')
plt.xlabel('面积（平方米）')
plt.ylabel('总价（万元）')

# 计算线性回归（可删掉）
coeffs = np.polyfit(df['面积'], df['总价（万元）'], 1)
poly_eqn = np.poly1d(coeffs)
# 绘制趋势线
plt.plot(df['面积'], poly_eqn(df['面积']), "r--", color='green')
plt.show()

#2
df = pd.read_csv('Buildings_finall_handle.csv')

# 确保没有缺失值
df = df.dropna(subset=['朝向', '总价（万元）'])

# 将总价字段转换为数值类型
df['总价（万元）'] = pd.to_numeric(df['总价（万元）'])

# 获取朝向类别的所有唯一值
orientation_categories = df['朝向'].unique()

# 为每个朝向类别选择不同的颜色
palette = sns.color_palette('hsv', len(orientation_categories))

# 绘制竖向箱线图，为每个箱体设置不同的颜色
plt.figure(figsize=(12, 6))  # 可以调整图形大小
sns.boxplot(y='朝向', x='总价（万元）', data=df, palette=palette)
plt.title('朝向与房产总价的箱线图')
plt.xlabel('总价（万元）')
plt.ylabel('朝向')

# 显示图表
plt.show()
#3
df = pd.read_csv('Buildings_finall_handle.csv')

# 确保没有缺失值
df = df.dropna(subset=['装修', '总价（万元）'])

# 将总价字段转换为数值类型
df['总价（万元）'] = pd.to_numeric(df['总价（万元）'])

# 将其简化为几个主要类别
装修条件映射 = {
   '精装修': '精装修',
   '简装修': '简装修',
   '毛坯': '毛坯',
   # 如果有其他装修情况，在这里添加映射
}
df['装修'] = df['装修'].map(装修条件映射)

# 获取装修条件类别的所有唯一值
decoration_categories = df['装修'].unique()

# 为每个装修条件类别选择不同的颜色
palette = sns.color_palette('hsv', len(decoration_categories))

# 绘制竖向箱线图，为每个箱体设置不同的颜色
plt.figure(figsize=(10, 6))  # 可以调整图形大小
sns.boxplot(y='装修', x='总价（万元）', data=df, palette=palette)
plt.title('装修条件与房产总价的箱线图')
plt.xlabel('总价（万元）')
plt.ylabel('装修条件')

# 显示图表
plt.show()

#4
df = pd.read_csv('Buildings_finall_handle.csv')

# 确保没有缺失值
df = df.dropna(subset=['楼层', '总价（万元）'])

# 将总价字段转换为数值类型
df['总价（万元）'] = pd.to_numeric(df['总价（万元）'])

# 将楼层字段转换为类别类型
df['楼层'] = df['楼层'].astype('category')

# 获取楼层类别的所有唯一值
floor_categories = df['楼层'].cat.categories

# 为每个楼层类别选择不同的颜色
palette = sns.color_palette('hsv', len(floor_categories))

# 绘制竖向箱线图，为每个箱体设置不同的颜色
plt.figure(figsize=(12, 8))
sns.boxplot(x='总价（万元）', y='楼层', data=df, palette=palette)
plt.title('不同楼层类别的房产总价分布')
plt.xlabel('总价（万元）')
plt.ylabel('楼层类别')

# 显示图表
plt.show()

#5
df = pd.read_csv('Buildings_finall_handle.csv')

# 确保没有缺失值
df = df.dropna(subset=['建筑年代', '总价（万元）'])

# 将总价字段转换为数值类型
df['总价（万元）'] = pd.to_numeric(df['总价（万元）'])

# 根据建筑年代分组并计算每组的平均总价
average_prices_by_year = df.groupby('建筑年代')['总价（万元）'].mean()

# 准备颜色列表，为每个柱体设置不同的颜色
colors = plt.cm.viridis(np.linspace(0, 1, len(average_prices_by_year))) # 使用viridis颜色映射

# 绘制柱状图
plt.figure(figsize=(12, 6))

# 反转颜色列表，以便颜色映射正确地应用到柱体上
colors = colors[::-1]

# 绘制每个柱体并指定颜色
for (i, (year, avg_price)) in enumerate(average_prices_by_year.items()):
    plt.bar(year, avg_price, color=colors[i])

plt.title('不同建筑年代的平均房产总价')
plt.xlabel('建筑年代')
plt.ylabel('平均总价（万元）')

# 确保x轴标签的可读性
plt.xticks(rotation=45)

# 显示图表
plt.show()



#6
df = pd.read_csv('Buildings_finall_handle.csv')

# 获取布局列的所有唯一值
layouts = df['布局'].unique()

# 确保没有缺失值
df = df.dropna(subset=['布局', '总价（万元）'])

# 将总价字段转换为数值类型
df['总价（万元）'] = pd.to_numeric(df['总价（万元）'])

# 为每个布局选择不同的颜色
palette = sns.color_palette('hsv', len(layouts))

# 绘制横向箱线图，为每个箱体设置不同的颜色
plt.figure(figsize=(12, 8))
sns.boxplot(x='总价（万元）', y='布局', data=df, orient='h', palette=palette)
plt.title('不同布局的房产总价分布')
plt.xlabel('总价（万元）')
plt.ylabel('布局')

# 显示图表
plt.show()

# ---------------------------------------------- 对离散型进行探索性分析 -------------------------------

import pandas as pd
import matplotlib.pyplot as plt

# 读取数据
file_path = "C:\\Users\\ASUS\\Desktop\\Buildings_finall_handle.csv"
house_data = pd.read_csv(file_path)

# 查看数据前几行以确认列名和数据类型
print(house_data.head())

# 选择几个离散型变量进行分析
discrete_columns = ['区域', '电梯', '产权性质', '住宅类别', '建筑结构', '建筑类别', '楼层', '布局', '朝向', '装修']

# 设置全局字体
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = ['SimHei']  # 你可以根据需要更改字体
plt.rcParams['font.size'] = 12

# 对每个离散型变量进行频数统计并可视化
for column in discrete_columns:
    counts = house_data[column].value_counts()
    print(f"{column} 频数统计：")
    print(counts)
    print("")

    # 可视化频数统计（条形图）
    if len(counts) > 5:  # 如果类别数量大于5，使用条形图
        counts.plot(kind='bar', color='pink')
        plt.title(f'{column} 频数分布 - 条形图', fontsize=14, fontweight='bold')
        plt.xlabel(column, fontsize=12, fontweight='bold')
        plt.ylabel('频数', fontsize=12, fontweight='bold')
        plt.xticks(rotation=45, ha="right", fontsize=10)  # 如果标签太长，旋转它们
        plt.tight_layout()  # 自动调整布局
        plt.grid(axis='y', linestyle='--', alpha=0.7)  # 添加网格线
        plt.show()
    else:  # 否则使用饼图
        counts.plot(kind='pie', autopct='%1.1f%%', startangle=90)
        plt.title(f'{column} 频数分布 - 饼图', fontsize=14, fontweight='bold')
        plt.ylabel('')
        plt.tight_layout()  # 自动调整布局
        plt.legend(loc='best', fontsize=10)  # 添加图例
        plt.show()


# ------------------------------------------------ 对相关性进行探索性分析---------------------------

from pylab import mpl
mpl.rcParams["axes.unicode_minus"] = False
mpl.rcParams['font.family'] = 'Microsoft YaHei'
from sklearn.preprocessing import MinMaxScaler
import seaborn as sns

# 读取CSV文件
df = pd.read_csv("Buildings_finall_handle.csv")

# 打印“区域”列中的唯一值
print(df['区域'].unique())

# 去除“区域”列中字符串的首尾空格
df['区域'] = df['区域'].str.strip()

# 定义一个替换字典，用于将“区域”列中的特定值替换为其他值
replace_dict = {
    '瑞辰玖阙': '兰州新区',
    '永登': '永登县',
    '瑞辰金悦府': '兰州新区',
    '海亮·公园学府': '兰州新区',
    '皋兰': '皋兰县',
    '新区万科城': '兰州新区',
    '远达锦绣半岛': '安宁区',
    '安宁': '安宁区',
    '安宁庭院': '安宁区',
    '酒泉御园飞天花苑住宅小区': '安宁区',
    '新厦水岸天成': '安宁区',
    '兰石豪布斯卡璟园': '七里河区',
    '七里河': '七里河区',
    '中和教育世家': '安宁区',
    '天泰世纪嘉园': '七里河区',
    '百合家园': '七里河区',
    '兰州恒大帝景': '七里河区'
}

# 使用replace方法替换“区域”列中的值
df['区域'] = df['区域'].replace(replace_dict)

# 打印替换后的“区域”列
print(df['区域'])

# 计算每个区域的平均总价
df.groupby("区域")['总价（万元）'].mean()

# 使用pivot_table方法创建透视表，计算每个区域和楼层的平均总价，主要用来检验替换效果。
df_ana = pd.pivot_table(df, values=['总价（万元）'], index=['区域', '楼层'], aggfunc='mean')
print(df_ana)

# 创建一个新列“经济发展水平”，并将其设置为与“区域”列相同的值
df['经济发展水平'] = df['区域']
#欲探索经济发展对房价的影响因素，通过了解2023年兰州各区收入水平，对地区进行数据替换
# 定义一个替换字典，用于将“经济发展水平”列中的特定值替换为数值

df['经济发展水平'] = df['区域']
replace_dict = {
    '兰州新区':374.3,
     '永登县':144.4,
     '皋兰县':67.3,
     '安宁区':305.81,
     '七里河区':610.87,
}

# 使用replace方法替换“经济发展水平”列中的值
df['经济发展水平'] = df['经济发展水平'].replace(replace_dict)
print(df['经济发展水平'])

# 定义要归一化的列
columns_to_normalize = ['经济发展水平', '面积', '单价(元/m²)', '总价（万元）', '层数']

# 创建一个MinMaxScaler对象
scaler = MinMaxScaler()

# 对指定的列进行归一化处理
df[columns_to_normalize] = scaler.fit_transform(df[columns_to_normalize])

# 提取归一化后的列，创建一个新的DataFrame
df_normalize = df[columns_to_normalize]

# 计算归一化后列的相关系数矩阵，并打印
print(df_normalize.corr())

# 定义要计算相关系数的列
selected_columns = ['经济发展水平', '面积', '单价(元/m²)', '总价（万元）', '层数']

# 计算选定列的相关系数矩阵
corr_matrix = df[selected_columns].corr()

# 打印相关系数矩阵
print(corr_matrix)

# 绘制热图，显示选定列的相关系数
plt.figure(figsize=(8, 6))

sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f')

plt.title('选定列的相关系数热图')

plt.savefig('chart.png')  # 保存热图为PNG文件

plt.show()  # 显示热图



# ------------------------------------------ 机器学习以及模型搭建-------------------------------------
# 导入所需的库
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import Lasso
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.neighbors import KNeighborsRegressor

# 加载数据集
file_path = r"Buildings_finall_handle.csv"
df = pd.read_csv(file_path)

# 删除所有缺失值
df = df.dropna().reset_index(drop=True)

# 分解户型
def apart_room(x):
    room = x.split('室')[0]
    return int(room)

def apart_hall(x):
    hall = x.split('厅')[0].split('室')[1]
    return int(hall)

def apart_wc(x):
    wc = x.split('卫')[0].split('厅')[1]
    return int(wc)

df['室'] = df['布局'].map(apart_room)
df['厅'] = df['布局'].map(apart_hall)
df['卫'] = df['布局'].map(apart_wc)

# 删除楼层、布局、单价(元/m2)
df.drop(columns=['楼层', '布局', '单价(元/m2)'], inplace=True)

# 编码-有序多分类（根据上面可视化的结果，按照对价格的影响程度排序，越大影响越高）
# 无序多分类无法直接引入，必须“哑元”化变量
# 等级变量（有序多分类）可以直接引入模型
map1 = {'南':5, '南北':6, '北':1, '西南':10, '东西':4, '东':2, '东北':8, '东南':9, '西':3, '西北':7}
df['朝向'] = df['朝向'].map(map1)
map2 = {'毛坯':1, '简装修':2, '精装修':3, '中装修':4, '豪华装修':5}
df['装修'] = df['装修'].map(map2)
map3 = {'有 ':1, '无 ':0}
df['电梯'] = df['电梯'].map(map3)
map4 = {'商品房':6, '个人产权':5, '商品房(免税)':7, '普通商品房':4, '经济适用房':2, '房改房':3, '限价房':8, '房本房':1}
df['产权性质'] = df['产权性质'].map(map4)
map5 = {'普通住宅':4, '经济适用房':3, '公寓':1, '商住楼':2, '酒店式公寓':5}
df['住宅类别'] = df['住宅类别'].map(map5)
map6 = {'平层':4, '开间':2, '跃层':5, '错层':1, '复式':3}
df['建筑结构'] = df['建筑结构'].map(map6)
map7 = {'板楼':4, '钢混':5, '塔板结合':3, '平房':6, '砖混':1, '塔楼':7, '砖楼':2}
df['建筑类别'] = df['建筑类别'].map(map7)
map8 = {'城关':6, '安宁':5, '七里河':4, '西固':3,'榆中':2, '永登':1}
df['区域'] = df['区域'].map(map8)

# 删除超过2019年的房子，年代转变为房龄
df['建筑年代'] = df['建筑年代'].fillna(0).astype('int32')
df.drop(index=df[df['建筑年代']>2019].index, inplace=True)
df['房龄'] = df['建筑年代'].map(lambda x: 2020-x)
df.drop(columns=['建筑年代'], inplace=True)

# 准备数据集
X = df.drop(columns=['总价（万元）'])
y = df['总价（万元）']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=33)


# 特征多项式扩展
poly = PolynomialFeatures(degree=2)
x_train = poly.fit_transform(X_train.values)
x_test = poly.transform(X_test.values)

# 套索回归
la = Lasso(alpha=0.1, max_iter=100000)
la.fit(x_train, y_train)
print(f'训练集得分：{round(la.score(x_train, y_train), 2)}')
print(f'测试集得分：{round(la.score(x_test, y_test), 2)}')

# 随机森林
rf = RandomForestRegressor()
rf.fit(x_train, y_train)
print(f'随机森林训练集得分：{round(rf.score(x_train, y_train), 2)}')
print(f'随机森林测试集得分：{round(rf.score(x_test, y_test), 2)}')

# 决策树
dt = DecisionTreeRegressor(max_depth=6)
dt.fit(x_train, y_train)
print(f'决策树训练集得分：{round(dt.score(x_train, y_train), 2)}')
print(f'决策树测试集得分：{round(dt.score(x_test, y_test), 2)}')

# k近邻
kn = KNeighborsRegressor(n_neighbors=20)
kn.fit(x_train, y_train)
print(f'k近邻训练集得分：{round(kn.score(x_train, y_train), 2)}')
print(f'k近邻测试集得分：{round(kn.score(x_test, y_test), 2)}')
